package com.mayflygeek.mayflyask.framework.orm.impl;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Collection;
import java.util.List;

import org.springframework.data.domain.Page;

import com.googlecode.genericdao.search.Field;
import com.googlecode.genericdao.search.Filter;
import com.googlecode.genericdao.search.ISearch;
import com.googlecode.genericdao.search.Sort;
import com.mayflygeek.mayflyask.framework.orm.BaseDao;
import com.mayflygeek.mayflyask.framework.orm.Query;

/**
 * @author 虫虫
 * @team 蜉蝣极客
 * @link www.mayflygeek.com
 * @Emial chongchong@mayflygeek.com
 * 
 */
public class QueryImpl<T, RT> implements Query<T, RT> {
	private final SearchBuilder _searchBuilder = SearchBuilder.get();

	private BaseDao<T, ?> baseDao;

	public QueryImpl(Class<T> searchClass) {
		this.searchClass(searchClass);
	}

	public QueryImpl(BaseDao<T, ?> baseDao) {
		this.baseDao = baseDao;
		this.searchClass(this.baseDao.getEntityClass());
	}

	public QueryImpl(BaseDao<T, ?> baseDao, Class<T> searchClass) {
		this.baseDao = baseDao;
		this.searchClass(searchClass);
	}

	public void setBaseDao(BaseDao<T, ?> baseDao) {
		this.baseDao = baseDao;
	}

	protected BaseDao<T, ?> getBaseDao() {
		return checkNotNull(baseDao, "请设置相应Dao!");
	}

	@Override
	public List<RT> list() {
		return getBaseDao().list(this);
	}

	@Override
	public Page<RT> page() {
		return getBaseDao().page(this);
	}

	@Override
	public RT first() {
		List<RT> list = list();
		if (!list.isEmpty()) {
			return list.get(0);
		}
		return null;
	}

	@Override
	public RT unique() {
		return getBaseDao().unique(this);
	}

	@Override
	public int count() {
		return getBaseDao().count(this);
	}

	@Override
	public Query<T, RT> searchClass(Class<T> searchClass) {
		_searchBuilder.setSearchClass(searchClass);
		return this;
	}

	@Override
	public Query<T, RT> page(int page) {
		_searchBuilder.setPage(page);
		return this;
	}

	@Override
	public Query<T, RT> page(int page, int pagesize) {
		_searchBuilder.setPage(page, pagesize);
		return this;
	}

	@Override
	public int thePage() {
		return this._searchBuilder.getPage();
	}

	@Override
	public Query<T, RT> pagesize(int pagesize) {
		return limit(pagesize);
	}

	@Override
	public int pagesize() {
		return this._searchBuilder.getPagesize();
	}

	@Override
	public Query<T, RT> start(int firstResult) {
		_searchBuilder.setStart(firstResult);
		return this;
	}

	@Override
	public Query<T, RT> limit(int limit) {
		_searchBuilder.setLimit(limit);
		return this;
	}

	@Override
	public Query<T, RT> start(int start, int limit) {
		_searchBuilder.setStart(start,limit);
		return this;
	}

	@Override
	public Query<T, RT> autoCount(boolean autoCount) {
		_searchBuilder.setAutoCount(autoCount);
		return this;
	}

	@Override
	public boolean autoCount() {
		return this._searchBuilder.isAutoCount();
	}

	@Override
	public Query<T, RT> filter(Filter filter) {
		_searchBuilder.addFilter(filter);
		return this;
	}

	@Override
	public Query<T, RT> filters(Filter... filters) {
		_searchBuilder.addFilters(filters);
		return this;
	}

	@Override
	public Query<T, RT> filterEqual(String property, Object value) {
		_searchBuilder.addFilterEqual(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterGreaterOrEqual(String property, Object value) {
		_searchBuilder.addFilterGreaterOrEqual(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterGreaterThan(String property, Object value) {
		_searchBuilder.addFilterGreaterThan(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterIn(String property, Collection<?> value) {
		_searchBuilder.addFilterIn(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterIn(String property, Object... value) {
		_searchBuilder.addFilterIn(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterNotIn(String property, Collection<?> value) {
		_searchBuilder.addFilterNotIn(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterNotIn(String property, Object... value) {
		_searchBuilder.addFilterNotIn(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterLessOrEqual(String property, Object value) {
		_searchBuilder.addFilterLessOrEqual(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterLessThan(String property, Object value) {
		_searchBuilder.addFilterLessThan(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterLike(String property, String value) {
		_searchBuilder.addFilterLike(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterILike(String property, String value) {
		_searchBuilder.addFilterILike(property, value);
		return this;
	}

	@Override
	public Query<T, RT> filterNull(String property) {
		_searchBuilder.addFilterNull(property);
		return this;
	}

	@Override
	public Query<T, RT> filterNotNull(String property) {
		_searchBuilder.addFilterNotNull(property);
		return this;
	}

	@Override
	public Query<T, RT> filterEmpty(String property) {
		_searchBuilder.addFilterEmpty(property);
		return this;
	}

	@Override
	public Query<T, RT> filterNotEmpty(String property) {
		_searchBuilder.addFilterNotEmpty(property);
		return this;
	}

	@Override
	public Query<T, RT> filterAnd(Filter... filters) {
		_searchBuilder.addFilterAnd(filters);
		return this;
	}

	@Override
	public Query<T, RT> filterOr(Filter... filters) {
		_searchBuilder.addFilterOr(filters);
		return this;
	}

	@Override
	public Query<T, RT> filterNot(Filter filter) {
		_searchBuilder.addFilterNot(filter);
		return this;
	}

	@Override
	public Query<T, RT> filterSome(String property, Filter filter) {
		_searchBuilder.addFilterSome(property, filter);
		return this;
	}

	@Override
	public Query<T, RT> filterAll(String property, Filter filter) {
		_searchBuilder.addFilterAll(property, filter);
		return this;
	}

	@Override
	public Query<T, RT> filterNone(String property, Filter filter) {
		_searchBuilder.addFilterNone(property, filter);
		return this;
	}

	@Override
	public Query<T, RT> removeFilter(Filter filter) {
		_searchBuilder.removeFilter(filter);
		return this;
	}

	@Override
	public Query<T, RT> removeFiltersOnProperty(String property) {
		_searchBuilder.removeFiltersOnProperty(property);
		return this;
	}

	@Override
	public Query<T, RT> clearFilters() {
		_searchBuilder.clearFilters();
		return this;
	}

	@Override
	public Query<T, RT> sort(Sort sort) {
		_searchBuilder.addSort(sort);
		return this;
	}

	@Override
	public Query<T, RT> sorts(Sort... sorts) {
		_searchBuilder.addSorts(sorts);
		return this;
	}

	@Override
	public Query<T, RT> sortAsc(String property) {
		_searchBuilder.addSortAsc(property);
		return this;
	}

	@Override
	public Query<T, RT> sortAsc(String property, boolean ignoreCase) {
		_searchBuilder.addSortAsc(property, ignoreCase);
		return this;
	}

	@Override
	public Query<T, RT> sortDesc(String property) {
		_searchBuilder.addSortDesc(property);
		return this;
	}

	@Override
	public Query<T, RT> sortDesc(String property, boolean ignoreCase) {
		_searchBuilder.addSortDesc(property, ignoreCase);
		return this;
	}
	
	@Override
	public Query<T, RT> sort(String property, boolean desc) {
		_searchBuilder.addSort(property, desc);
		return this;
	}

	@Override
	public Query<T, RT> sort(String property, boolean desc, boolean ignoreCase) {
		_searchBuilder.addSort(property, desc, ignoreCase);
		return this;
	}

	@Override
	public Query<T, RT> removeSort(Sort sort) {
		_searchBuilder.removeSort(sort);
		return this;
	}

	@Override
	public Query<T, RT> removeSort(String property) {
		_searchBuilder.removeSort(property);
		return this;
	}

	@Override
	public Query<T, RT> clearSorts() {
		_searchBuilder.clearSorts();
		return this;
	}

	@Override
	public Query<T, RT> field(Field field) {
		_searchBuilder.addField(field);
		return this;
	}

	@Override
	public Query<T, RT> fields(Field... fields) {
		_searchBuilder.addFields(fields);
		return this;
	}

	@Override
	public Query<T, RT> field(String property, String key) {
		_searchBuilder.addField(property, key);
		return this;
	}

	@Override
	public Query<T, RT> field(String property, int operator) {
		_searchBuilder.addField(property, operator);
		return this;
	}

	@Override
	public Query<T, RT> field(String property, int operator, String key) {
		_searchBuilder.addField(property, operator, key);
		return this;
	}

	@Override
	public Query<T, RT> removeField(Field field) {
		_searchBuilder.removeField(field);
		return this;
	}

	@Override
	public Query<T, RT> removeField(String property) {
		_searchBuilder.removeField(property);
		return this;
	}

	@Override
	public Query<T, RT> removeField(String property, String key) {
		_searchBuilder.removeField(property, key);
		return this;
	}

	@Override
	public Query<T, RT> clearFields() {
		_searchBuilder.clearFields();
		return this;
	}

	@Override
	public Query<T, RT> distinct(boolean distinct) {
		_searchBuilder.setDistinct(distinct);
		return this;
	}

	@Override
	public Query<T, RT> resultMode(int resultMode) {
		_searchBuilder.setResultMode(resultMode);
		return this;
	}

	@Override
	public Query<T, RT> fetch(String property) {
		_searchBuilder.addFetch(property);
		return this;
	}

	@Override
	public Query<T, RT> fetches(String... propeties) {
		_searchBuilder.addFetches(propeties);
		return this;
	}

	@Override
	public Query<T, RT> removeFetch(String property) {
		_searchBuilder.removeFetch(property);
		return this;
	}

	@Override
	public Query<T, RT> clearFetches() {
		_searchBuilder.clearFetches();
		return this;
	}

	@Override
	public Query<T, RT> clear() {
		_searchBuilder.clear();
		return this;
	}

	@Override
	public Query<T, RT> clearPaging() {
		_searchBuilder.clearPaging();
		return this;
	}

	@Override
	public ISearch toSearch() {
		return this._searchBuilder.build();
	}

}
